import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ArrayBlockingQueue;

/*
 * MNBClassifier.java
 * Author: Guannan ZHang
 * Usage: IR HW4: This class is subclass of AbstractClassifier. it overrides the train() method MNB model.
 */
public class MNBClassifier extends AbstractClassifier {

	public MNBClassifier() {
		super();
		
	}

	public static void main(String[] args) {
		AbstractClassifier classifier = new MNBClassifier();
		classifier.train("citeseer.train.txt");
		classifier.classify("citeseer.test.txt");
		classifier.evaluate();
	}

	/*
	 *  overrides the train() method using MNB model
	 */
	public void train(String file) {
		try {
			// total number of training documents
			int docNum = 0;
			// number of documents in each category
			HashMap<Integer, Integer> docNumInClass = new HashMap<Integer, Integer>();
			// term number in each category
			HashMap<Integer, HashMap<Integer, Double>> termNumInClass = new HashMap<Integer, HashMap<Integer, Double>>();
			// total term number in each category
			HashMap<Integer, Double> totalInClass = new HashMap<Integer, Double>();
			// terms appearing in all categories
			HashSet<Integer> terms = new HashSet<Integer>();
			// all categories
			HashSet<Integer> totalClasses = new HashSet<Integer>();

			BufferedReader br = new BufferedReader(new FileReader(file));
			String line;
			while ((line = br.readLine()) != null) {

				String[] str = line.split(" ");
				// System.out.println(str[0]);
				String[] classes = str[0].split(",");
				for (int i = 0; i < classes.length; i++) {
					docNum++;
					int c = Integer.parseInt(classes[i]);

					if (!totalClasses.contains(c)) {
						totalClasses.add(c);
						// System.out.println(totalClasses);
					}

					if (docNumInClass.containsKey(c)) {
						docNumInClass.put(c, docNumInClass.get(c) + 1);
					} else {
						docNumInClass.put(c, 1);
					}

					HashMap<Integer, Double> termNum;
					if (termNumInClass.containsKey(c)) {
						termNum = termNumInClass.get(c);
					} else {
						termNum = new HashMap<Integer, Double>();
						termNumInClass.put(c, termNum);
					}

					double total = 0.0;
					for (int j = 1; j < str.length - 2; j++) {
						// System.out.println(str[i]);
						String[] pair = str[j].split(":");
						int term = Integer.parseInt(pair[0]);
						double times = Double.parseDouble(pair[1]);

						if (!terms.contains(term)) {
							terms.add(term);
						}

						total += times;
						// System.out.println(docID);
						if (termNum.containsKey(term)) {
							termNum.put(term, termNum.get(term) + times);
						} else {
							termNum.put(term, times);
						}
					}

					if (totalInClass.containsKey(c)) {
						totalInClass.put(c, totalInClass.get(c) + total);
					} else {
						totalInClass.put(c, total);
					}
				}

			}

			// System.out.println(docNum);
			// System.out.println(docNumInClass);
			// System.out.println(termNumInClass);
			// System.out.println(totalInClass);

			br.close();

			classNum = totalClasses.size();
			int v = terms.size();
			// System.out.println(v);
			for (Iterator<Entry<Integer, Integer>> it = docNumInClass
					.entrySet().iterator(); it.hasNext();) {
				Entry<Integer, Integer> e = it.next();
				pc.put(e.getKey(), (double) e.getValue() / (double) docNum);
			}

			for (Iterator<Entry<Integer, Double>> it = totalInClass.entrySet()
					.iterator(); it.hasNext();) {
				Entry<Integer, Double> e = it.next();
				int c = e.getKey();
				double total = e.getValue();

				HashMap<Integer, Double> termNum = termNumInClass.get(c);
				HashMap<Integer, Double> pt = new HashMap<Integer, Double>();
				ptc.put(c, pt);

				for (Iterator<Integer> iter = terms.iterator(); iter.hasNext();) {
					int term = iter.next();
					if (termNum.containsKey(term)) {
						pt.put(term, (termNum.get(term) + 1.0) / (total + v));

					} else {
						pt.put(term, 1.0 / (total + v));
					}
				}

			}
//			HashMap<Integer, Double> features = ptc.get(16);
//			int n = features.size();
//			ArrayList<Integer> list = new ArrayList<Integer>();
//			for(int i = 1; i<=n; i++){
//				list.add(i);
//			}
//			
//			//System.out.println(list);
//			Collections.sort(list, new MyComparator(features));
//
//			for(int i = 0; i < 5; i++){
//				System.out.println(list.get(i) + "\t" + features.get(list.get(i)));
//			}
			
			// System.out.println(pc);
			// System.out.println(ptc);

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	
}
